package com.docMan.dao.impl;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.FutureTask;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

import com.docMan.bean.Page;
import com.docMan.dao.BaseDao;
import com.docMan.utils.GenericsUtils;
import com.docMan.utils.ProjectUtils;
import com.google.code.ssm.api.ParameterValueKeyProvider;
import com.google.code.ssm.api.ReadThroughSingleCache;

@Repository
public class BaseDaoImpl<T> extends HibernateDaoSupport implements BaseDao<T> {
	protected Log logger =LogFactory.getLog(BaseDaoImpl.class);
	@SuppressWarnings("unchecked")
	protected Class<T> clazz=GenericsUtils.getSuperClassGenricType(this.getClass());
	
	@Resource(name = "sessionFactory")
	public void setSuperSessionFactory(SessionFactory sessionFactory){
		super.setSessionFactory(sessionFactory);
	}
	
	@Override
	public void delete(int id) {
		
		Object object=(Object) getCSession().get(clazz, id);
		getCSession().delete(object);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public T getById(Serializable id) {
		return (T)getCSession().get(clazz, id);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	/*@ReadThroughSingleCache(namespace="com.dangan.dao.impl",expiration=1800)*/
	public List<T> findAll( String key) {
		return getCSession().createQuery("from "+clazz.getSimpleName()).list();
	}
	
	@Override
	public List<T> findByIds(String[] ids) {
		
		return null;
	}

	@Override
	public int save(T entity) {
		getCSession().save(entity);
		return 1;
	}
	
	@Override
	public void update(T entity) {
		getCSession().update(entity);
	}
	
	public Session getCSession(){
		return getHibernateTemplate().getSessionFactory().getCurrentSession();//getCurrentSession();
	}
	
	public Session getNSession(){
		return getHibernateTemplate().getSessionFactory().openSession();
	}
	
	@SuppressWarnings("unchecked")
	@Override
	/*@ReadThroughSingleCache(namespace = "com.dang.dao.impl", expiration = 1800)*/
	public List<T> find( String key, String hql) {
		
		return (List<T>) getHibernateTemplate().find(hql);
		
	}
	
	@Override
	/*@ReadThroughSingleCache(namespace = "com.dang.dao.impl", expiration = 1800)*/
	public List<T> find( String key ,String hql,Object... values) {
		@SuppressWarnings("unchecked")
		List<T> lists=(List<T>)this.getHibernateTemplate().find(hql, values);
		return lists;
	}
	
	
	@SuppressWarnings("unchecked")
	@Override
	public List<T> query(String hql) {
		return createQuery(hql).list();
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<T> query(String hql, int page, int pageSize) {
		return createQuery(hql, page,pageSize).list();
	}
	
	
	@SuppressWarnings("unchecked")
	@Override
	public List<T> query(String hql, Object... objects) {

		return createQuery(hql, objects).list();
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<T> pageQuery(String hql, int page, int pageSize, Object... objects) {
		return createQuery(hql, page, pageSize, objects).list();
	}
	
	public Query createQuery(String hql){
		Query query=getCSession().createQuery(hql);
		return query;
	}
	
	public Query createQuery(String hql,Object...objects){
		Query query=getCSession().createQuery(hql);
		for(int i=0;i<objects.length;i++){
			query.setParameter(i, objects[i]);
		}
		return query; 
	}
	public Query createQuery(String hql,List<String> classes,List<String> objects){
		Query query=getCSession().createQuery(hql);
		for(int i=0;i<objects.size();i++){
				switch (classes.get(i)) {
					case "Double":
						query.setParameter(i, Double.parseDouble(objects.get(i).toString()));
						break;
					case "Integer":
						query.setParameter(i, Integer.parseInt(objects.get(i).toString()));
						break;
					default:
						query.setParameter(i, objects.get(i));
						break;
				}
		}
		return query; 
	}
	public Query createQuery(String hql,int page,int PageSize){
		Query query=getCSession().createQuery(hql);
		query.setFirstResult((page-1)*PageSize);
		query.setMaxResults(PageSize);
		return query;
	}
	public Query createQuery(String hql,int page,int PageSize,Object... objects){
		Query query=getCSession().createQuery(hql);
		query.setFirstResult((page-1)*PageSize);
		query.setMaxResults(PageSize);
		for(int i=0;i<objects.length;i++){
			query.setParameter(i, objects[i]);
		}
		return query;
	}
	
	@Override
	public List<T> createCriteria(int page, int pageSize,
			Map<String, Object> map) {
		@SuppressWarnings("unchecked")
		List<T> list=getCSession().createCriteria(getClass())
		.add( Restrictions.allEq(map))
		.setFirstResult((page-1)*pageSize)
		.setMaxResults(pageSize).list();
		return list;
	}

	@Override
	public List<T> createCriteria(Map<String, Object> map) {
		@SuppressWarnings("unchecked")
		List<T> list=getCSession().createCriteria(getClass())
				.add(Restrictions.allEq(map))
				.list();
		return list;
	}

	@Override
	public int excudeSqlUpdate(String sql, Object... objects) {
		Query query=getCSession().createSQLQuery(sql);
		for(int i=0;i<objects.length;i++){
			query.setParameter(i, objects[i]);
		}
		return query.executeUpdate();
	}
	
	@Override
	public int update(String hql, Object... objects) {
		Query query=getCSession().createQuery(hql);
		for(int i=0;i<objects.length;i++){
			query.setParameter(i, objects[i]);
		}
		return query.executeUpdate();
	}
	
	@SuppressWarnings("unused")
	private int getRowCount(String hql,Object...objects){
		return getHibernateTemplate().find(hql, objects).size();
	}
	
	@SuppressWarnings({ "unchecked" })
	@Override
	public Page<T> page(String hql,Page<T> page) {
		Session session=getCSession();
		Query query=session.createQuery(hql);
		Map<String, Object> params=page.getParams();
		int position=0;
		for (String param : params.keySet()) {
			if(Integer.parseInt(params.get(param).toString())!=0){
				if(!param.endsWith("year")&&!param.endsWith("Id")&&!param.endsWith("id")&&!param.endsWith("score")&&!param.endsWith("Score")&&!param.endsWith("State")&&!param.endsWith("state")&&!param.endsWith("ype")){
					query.setParameter(position, params.get(param));
				}else{
					query.setParameter(position, Integer.parseInt(params.get(param).toString()));
				}
				position++;
			}
		}
		//int rowCount=query.list().size();
		query.setFirstResult((page.getCurrentPage()-1)*page.getEveryPage());
		query.setMaxResults(page.getEveryPage()); 
		List<T> list=query.list();
		int rowCount=list.size();
		page.initPage(page.getEveryPage(), rowCount, page.getCurrentPage());
		page.setResult(list);
		session.close();
		return page;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	/*@ReadThroughSingleCache(namespace="com.dang.dao.impl",expiration=1800)*/
	public Page<T> restPage(String key,final String hql,final Page<T> page) {
		if(page.getEveryPage()==0){
			page.setEveryPage(13);
		}
		try {
			
			Query query=getCSession().createQuery(hql);
			Map<String, Object> params=page.getParams();
			for(int i=0;i<page.getParamsOrder().size();i++){
				query.setParameter(i, params.get(page.getParamsOrder().get(i)));
			}
			int rowCount=0;
			String rowKey=ProjectUtils.getRowCountKey(hql, page.getParams());
			FutureTask<Integer> rowCounTask;
			query.setFirstResult(((page.getCurrentPage()-1)<0?0:(page.getCurrentPage()-1))*page.getEveryPage());
			query.setMaxResults(page.getEveryPage());
			List<T> list;
			/*if(MemcachedUtils.get(rowKey)!=null){
				rowCount=Integer.parseInt(MemcachedUtils.get(rowKey).toString());
				list=query.list();
			}else{*/
				/*final Session session=getNSession();
				rowCounTask=new FutureTask<>(new Callable<Integer>() {
					@Override
					public Integer call() throws Exception {
						return getRowCount(hql, page,session);
					}
				});
				Thread thread=new Thread(rowCounTask);
				thread.start();*/
				list=query.list();
				/*try {
					rowCount=rowCounTask.get();
				} catch (InterruptedException e) {
					e.printStackTrace();
					rowCount=getRowCount(hql, page);
					session.close();
				} catch (ExecutionException e) {
					e.printStackTrace();
					rowCount=getRowCount(hql, page);
					session.close();
				}
				session.close();*/
				rowCount=getRowCount(hql, page);
//				MemcachedUtils.set(rowKey, rowCount, new Date(1000*300));
//			}
			page.initPage(page.getEveryPage(), rowCount, page.getCurrentPage());
			page.setResult(list);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return page;
	}
	public int getRowCount(String hql,Page<T> page){
		String hqlsString="select count(*) from"+hql.split("from")[1];
		Query query=getCSession().createQuery(hqlsString);
		Map<String, Object> params=page.getParams();
		for(int i=0;i<page.getParamsOrder().size();i++){
			query.setParameter(i, params.get(page.getParamsOrder().get(i)));
		}
		return Integer.parseInt(query.uniqueResult().toString()); 
	}
	/**
	 * 
	 * @param hql
	 * @param page
	 * @return
	 */
	public int getRowCount(String hql,Page<T> page,Session session){
		String hqlsString="select count(*) from"+hql.split("from")[1];
		Query query=session.createQuery(hqlsString);
		Map<String, Object> params=page.getParams();
		for(int i=0;i<page.getParamsOrder().size();i++){
			query.setParameter(i, params.get(page.getParamsOrder().get(i)));
		}
		return Integer.parseInt(query.uniqueResult().toString()); 
	}

	@Override
	public int update(String hql) {
		Query query=getCSession().createQuery(hql);
		return  query.executeUpdate();
	}

	@Override
	public int excudeSql(String sql) {
		Query query=getCSession().createSQLQuery(sql);
		return query.executeUpdate();
	}

	@Override
	public void saveOrUpdateAll(List<T> list) {
		//getHibernateTemplate().saveOrUpdate(list);
		
		Session session=getCSession();
		int i=0;
		for (T t : list) {
			session.saveOrUpdate(t);
			if(i%30==0){
				session.flush();
				session.clear();
			}
		}
		session.flush();
	}
	
	@Override
	public void saveOrUpdate(T entity) {
		getHibernateTemplate().saveOrUpdate(entity);
	}
	
	
	@Override
	public void  delete(T entity) {
		getHibernateTemplate().delete(entity);
	}

	@Override
	public int queryBySql(String sql) {
		
		return 0;
	}


	@SuppressWarnings("unchecked")
	@Override
	public List<T> find(String hql, List<String> params) {
		Query query=getCSession().createQuery(hql);
		
		for (int i = 0; i < params.size(); i++) {
			query.setParameter(i, params.get(i));
		}
		return query.list();
	}

	@Override
	public long count(String hql, Object... objects) {
		Query query=createQuery(hql, objects);
		Long number=(Long) query.list().get(0);
		return number;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> find(String hql, List<String> classes, List<String> params) {
		Query query=createQuery(hql, classes, params);
		
		return query.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> findAll() {
		return getCSession().createQuery("from "+clazz.getSimpleName()).list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> findNoCache(String hql) {
		return (List<T>) getHibernateTemplate().find(hql);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> findNoCache(String hql, Object... objects) {
		List<T> lists=(List<T>)this.getHibernateTemplate().find(hql, objects);
		return lists;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Page<T> restPageNoCache(String hql, Page<T> page) {
		Query query=getCSession().createQuery(hql);
		Map<String, Object> params=page.getParams();
		for(int i=0;i<page.getParamsOrder().size();i++){
			query.setParameter(i, params.get(page.getParamsOrder().get(i)));
		}
		int rowCount=query.list().size();
		query.setFirstResult(((page.getCurrentPage()-1)<0?0:(page.getCurrentPage()-1))*8);
		query.setMaxResults(8); 
		List<T> list=query.list();
		
		page.initPage(8, rowCount, page.getCurrentPage());
		page.setResult(list);
		return page;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object> findSqlNoCache(String sql, Object... objects) {
		Query sqlQuery=getCSession().createSQLQuery(sql);
		for (int i = 0; i < objects.length; i++) {
			sqlQuery.setParameter(i, objects[i]);
		}
		return sqlQuery.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object> findSqlNoCache(String sql) {
		Query sqlQuery=getCSession().createSQLQuery(sql);
		
		return sqlQuery.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<List> find(String hqlString) {
		Query query=getCSession().createQuery(hqlString);
		
		return query.list();
	}

	@Override
	public Query getQuery(String hql) {
		Query query=getHibernateTemplate().getSessionFactory().openSession().createQuery(hql);
		return query;
	}

	@Override
	public Page<T> newPage(Page<T> page,Query query) {
		int rowCount=query.list().size();
		query.setFirstResult((page.getCurrentPage()-1)*page.getEveryPage());
		query.setMaxResults(page.getEveryPage()); 
		List<T> list=query.list();
		//int rowCount=list.size();
		page.initPage(page.getEveryPage(), rowCount, page.getCurrentPage());
		page.setResult(list);
		return page;
	}

	@Override
	public List<List> find(Query query) {
		return query.list();
	}
	

	
	
}


